
/*
 * Copyright 2002-2023 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 *版权所有2002-2023原作者。
 *
 *根据Apache许可证2.0版许可（“许可证”）；
 *除非符合许可证的规定，否则您不得使用此文件。
 *您可以在以下网址获取许可证副本：
 *
 *https://www.apache.org/licenses/LICENSE-2.0
 *
 *除非适用法律要求或书面同意，软件
 *根据许可证进行的分发是在“按原样”的基础上进行的，
 *无任何明示或暗示的保证或条件。
 *有关管理权限的特定语言，请参阅许可证和
 *许可证下的限制。
 */

package org.springframework.jmx.export;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.management.DynamicMBean;
import javax.management.JMException;
import javax.management.MBeanException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.StandardMBean;
import javax.management.modelmbean.ModelMBean;
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.modelmbean.RequiredModelMBean;

import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.target.LazyInitTargetSource;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.Constants;
import org.springframework.jmx.export.assembler.AutodetectCapableMBeanInfoAssembler;
import org.springframework.jmx.export.assembler.MBeanInfoAssembler;
import org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler;
import org.springframework.jmx.export.naming.KeyNamingStrategy;
import org.springframework.jmx.export.naming.ObjectNamingStrategy;
import org.springframework.jmx.export.naming.SelfNaming;
import org.springframework.jmx.export.notification.ModelMBeanNotificationPublisher;
import org.springframework.jmx.export.notification.NotificationPublisherAware;
import org.springframework.jmx.support.JmxUtils;
import org.springframework.jmx.support.MBeanRegistrationSupport;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

/**
 * JMX exporter that allows for exposing any <i>Spring-managed bean</i> to a
 * JMX {@link javax.management.MBeanServer}, without the need to define any
 * JMX-specific information in the bean classes.
 *
 * <p>If a bean implements one of the JMX management interfaces, MBeanExporter can
 * simply register the MBean with the server through its autodetection process.
 *
 * <p>If a bean does not implement one of the JMX management interfaces, MBeanExporter
 * will create the management information using the supplied {@link MBeanInfoAssembler}.
 *
 * <p>A list of {@link MBeanExporterListener MBeanExporterListeners} can be registered
 * via the {@link #setListeners(MBeanExporterListener[]) listeners} property, allowing
 * application code to be notified of MBean registration and unregistration events.
 *
 * <p>This exporter is compatible with MBeans as well as MXBeans.
 *
 * @author Rob Harrop
 * @author Juergen Hoeller
 * @author Rick Evans
 * @author Mark Fisher
 * @author Stephane Nicoll
 * @since 1.2
 * @see #setBeans
 * @see #setAutodetect
 * @see #setAssembler
 * @see #setListeners
 * @see org.springframework.jmx.export.assembler.MBeanInfoAssembler
 * @see MBeanExporterListener
 */
/**
 *JMX导出器，允许向
 *JMX｛@link javax.management.MBeanServer｝，无需定义任何
 *bean类中特定于JMX的信息。
 *
 *＜p＞如果bean实现了其中一个JMX管理接口，那么MBeanExporter可以
 *只需通过服务器的自动检测过程向服务器注册MBean。
 *
 *<p>如果bean没有实现JMX管理接口之一，则MBeanExporter
 *将使用提供的｛@link MBeanInfoAssembler｝创建管理信息。
 *
 *<p>可以注册｛@link MBeanExporterListener MBeanExporter Listeners｝的列表
 *通过｛@link#setListeners（MBeanExporterListener[]）listeners｝属性，允许
 *要通知MBean注册和注销事件的应用程序代码。
 *
 *<p>此导出程序与MBean以及MXBeans兼容。
 *
 *@作者Rob Harrop
 *@作者于尔根·霍勒
 *@作者Rick Evans
 *@作者Mark Fisher
 *@作者Stephane Nicoll
 *@自1.2起
 *@见#setBeans
 *@参见#setAutodetect
 *@参见#setAssembler
 *@参见#setListeners
 *@参见org.springframework.jmx.export.assembler.MBeanInfoAssembler
 *@参见MBeanExporterListener
 */
public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExportOperations,
		BeanClassLoaderAware, BeanFactoryAware, InitializingBean, SmartInitializingSingleton, DisposableBean {

	/**
	 * Autodetection mode indicating that no autodetection should be used.
	 */
	/**
	 *指示不应使用自动检测的自动检测模式。
	 */
	public static final int AUTODETECT_NONE = 0;

	/**
	 * Autodetection mode indicating that only valid MBeans should be autodetected.
	 */
	/**
	 *自动检测模式，指示只应自动检测有效的MBean。
	 */
	public static final int AUTODETECT_MBEAN = 1;

	/**
	 * Autodetection mode indicating that only the {@link MBeanInfoAssembler} should be able
	 * to autodetect beans.
	 */
	/**
	 *自动检测模式指示只有｛@link MBeanInfoAssembler｝才能
	 *以自动检测bean。
	 */
	public static final int AUTODETECT_ASSEMBLER = 2;

	/**
	 * Autodetection mode indicating that all autodetection mechanisms should be used.
	 */
	/**
	 *自动检测模式，指示应使用所有自动检测机制。
	 */
	public static final int AUTODETECT_ALL = AUTODETECT_MBEAN | AUTODETECT_ASSEMBLER;


	/**
	 * Wildcard used to map a {@link javax.management.NotificationListener}
	 * to all MBeans registered by the {@code MBeanExporter}.
	 */
	/**
	 *用于映射｛@link javax.management.NotificationListener｝的通配符
	 *到｛@code MBeanExporter｝注册的所有MBean。
	 */
	private static final String WILDCARD = "*";

	/** Constant for the JMX {@code mr_type} "ObjectReference". */
	private static final String MR_TYPE_OBJECT_REFERENCE = "ObjectReference";

	/** Prefix for the autodetect constants defined in this class. */
	private static final String CONSTANT_PREFIX_AUTODETECT = "AUTODETECT_";


	/** Constants instance for this class. */
	private static final Constants constants = new Constants(MBeanExporter.class);

	/** The beans to be exposed as JMX managed resources, with JMX names as keys. */
	@Nullable
	private Map<String, Object> beans;

	/** The autodetect mode to use for this MBeanExporter. */
	@Nullable
	private Integer autodetectMode;

	/** Whether to eagerly initialize candidate beans when autodetecting MBeans. */
	private boolean allowEagerInit = false;

	/** Stores the MBeanInfoAssembler to use for this exporter. */
	private MBeanInfoAssembler assembler = new SimpleReflectiveMBeanInfoAssembler();

	/** The strategy to use for creating ObjectNames for an object. */
	private ObjectNamingStrategy namingStrategy = new KeyNamingStrategy();

	/** Indicates whether Spring should modify generated ObjectNames. */
	private boolean ensureUniqueRuntimeObjectNames = true;

	/** Indicates whether Spring should expose the managed resource ClassLoader in the MBean. */
	private boolean exposeManagedResourceClassLoader = true;

	/** A set of bean names that should be excluded from autodetection. */
	private final Set<String> excludedBeans = new HashSet<>();

	/** The MBeanExporterListeners registered with this exporter. */
	@Nullable
	private MBeanExporterListener[] listeners;

	/** The NotificationListeners to register for the MBeans registered by this exporter. */
	@Nullable
	private NotificationListenerBean[] notificationListeners;

	/** Map of actually registered NotificationListeners. */
	private final Map<NotificationListenerBean, ObjectName[]> registeredNotificationListeners = new LinkedHashMap<>();

	/** Stores the ClassLoader to use for generating lazy-init proxies. */
	@Nullable
	private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();

	/** Stores the BeanFactory for use in autodetection process. */
	@Nullable
	private ListableBeanFactory beanFactory;


	/**
	 * Supply a {@code Map} of beans to be registered with the JMX
	 * {@code MBeanServer}.
	 * <p>The String keys are the basis for the creation of JMX object names.
	 * By default, a JMX {@code ObjectName} will be created straight
	 * from the given key. This can be customized through specifying a
	 * custom {@code NamingStrategy}.
	 * <p>Both bean instances and bean names are allowed as values.
	 * Bean instances are typically linked in through bean references.
	 * Bean names will be resolved as beans in the current factory, respecting
	 * lazy-init markers (that is, not triggering initialization of such beans).
	 * @param beans a Map with JMX names as keys and bean instances or bean names
	 * as values
	 * @see #setNamingStrategy
	 * @see org.springframework.jmx.export.naming.KeyNamingStrategy
	 * @see javax.management.ObjectName#ObjectName(String)
	 */
	/** Constant for the JMX {@code mr_type} "ObjectReference". */
	private static最终字符串MR_TYPE_OBJECT_REFERENCE=“ObjectReference”；

	/**此类中定义的自动检测常量的前缀*/
	private static最终字符串CONSTANT_PREFIX_AUTODETECT=“AUTODETECT_”；


	/**此类的常量实例*/
	private static final常量=新常量（MBeanExporter.class）；

	/**将作为JMX托管资源公开的bean，并将JMX名称作为键*/
	@可为null
	private映射＜String，Object＞bean；

	/**用于此MBeanExporter的自动检测模式*/
	@可为null
	private Integer自动检测模式；

	/**在自动检测MBean时是否急切地初始化候选bean*/
	private布尔值allowEagleInit=false；

	/**存储用于此导出器的MBeanInfoAssembler*/
	private MBeanInfoAssembler汇编器=new SimpleReflectiveMBeanInfoAssemblyler（）；

	/**用于为对象创建ObjectNames的策略*/
	private ObjectNamingStrategy namingStrategy=新的KeyNamingStrategie（）；

	/**指示Spring是否应修改生成的ObjectNames*/
	private boolean ensureUniqueRuntimeObjectNames=true；

	/**指示Spring是否应在MBean中公开托管资源ClassLoader*/
	private boolean exposeManageResourceClassLoader=true；

	/**应该从自动检测中排除的一组bean名称*/
	private final Set＜String＞excludedBeans＝new HashSet＜＞（）；

	/**MBeanExporterListeners在此出口商处注册*/
	@可为null
	private MBeanExporterListener[]侦听器；

	/**用于注册此导出程序注册的MBean的NotificationListeners*/
	@可为null
	private NotificationListenerBean[]notificationListeners；

	/**实际注册的NotificationListeners的映射*/
	private final Map＜NotificationListenerBean，ObjectName〔〕＞registeredNotificationListeners＝new LinkedHashMap＜＞（）；

	/**存储用于生成惰性init代理的ClassLoader*/
	@可为null
	private ClassLoader beanClassLoader=ClassUtils.getDefaultClassLoader（）；

	/**存储BeanFactory以用于自动检测过程*/
	@可为null
	私有ListableBeanFactory豆工厂；


	/**
	 *提供要向JMX注册的bean的{@code-Map}
	 *｛@code MBeanServer｝。
	 *＜p＞字符串键是创建JMX对象名称的基础。
	 *默认情况下，将直接创建JMX｛@code ObjectName｝
	 *从给定的密钥。这可以通过指定
	 *自定义{@code命名策略}。
	 *＜p＞bean实例和bean名称都允许作为值。
	 *Bean实例通常通过Bean引用链接进来。
	 *Bean名称将在当前工厂中解析为Bean，尊重
	 *惰性init标记（也就是说，不触发此类bean的初始化）。
	 *@param-beans一个以JMX名称作为键和bean实例或bean名称的Map
	 *作为值
	 *@参见#setNamingStrategy
	 *@参见org.springframework.jmx.export.naming.KeyNamingStrategy
	 *@参见javax.management.ObjectName#ObjectName（字符串）
	 */
	public void setBeans(Map<String, Object> beans) {
		this.beans = beans;
	}

	/**
	 * Set whether to autodetect MBeans in the bean factory that this exporter
	 * runs in. Will also ask an {@code AutodetectCapableMBeanInfoAssembler}
	 * if available.
	 * <p>This feature is turned off by default. Explicitly specify
	 * {@code true} here to enable autodetection.
	 * @see #setAssembler
	 * @see AutodetectCapableMBeanInfoAssembler
	 * @see #isMBean
	 */
	/**
	 *设置是否在该导出器所在的bean工厂中自动检测MBean
	 *在中运行。还将询问｛@code AutodetectCapableMBeanInfoAssembler｝
	 *如果可用的话。
	 *<p>此功能在默认情况下处于禁用状态。明确指定
	 *｛@code true｝在此处启用自动检测。
	 *@参见#setAssembler
	 *@请参阅AutodetectCapableMBeanInfoAssembler
	 *@参见#isMBean
	 */
	public void setAutodetect(boolean autodetect) {
		this.autodetectMode = (autodetect ? AUTODETECT_ALL : AUTODETECT_NONE);
	}

	/**
	 * Set the autodetection mode to use.
	 * @throws IllegalArgumentException if the supplied value is not
	 * one of the {@code AUTODETECT_} constants
	 * @see #setAutodetectModeName(String)
	 * @see #AUTODETECT_ALL
	 * @see #AUTODETECT_ASSEMBLER
	 * @see #AUTODETECT_MBEAN
	 * @see #AUTODETECT_NONE
	 */
	/**
	 *设置要使用的自动检测模式。
	 *如果提供的值不是，@throws IllegalArgumentException
	 *｛@code AUTODETECT_｝常量之一
	 *@参见#setAutodetectModeName（字符串）
	 *@参见#AUTODETECT_ALL
	 *@参见#AUTODETECT_ASSEMBLER
	 *@参见#AUTODETECT_MBEAN
	 *@参见#AUTODETECT_NONE
	 */
	public void setAutodetectMode(int autodetectMode) {
		if (!constants.getValues(CONSTANT_PREFIX_AUTODETECT).contains(autodetectMode)) {
			throw new IllegalArgumentException("Only values of autodetect constants allowed");
		}
		this.autodetectMode = autodetectMode;
	}

	/**
	 * Set the autodetection mode to use by name.
	 * @throws IllegalArgumentException if the supplied value is not resolvable
	 * to one of the {@code AUTODETECT_} constants or is {@code null}
	 * @see #setAutodetectMode(int)
	 * @see #AUTODETECT_ALL
	 * @see #AUTODETECT_ASSEMBLER
	 * @see #AUTODETECT_MBEAN
	 * @see #AUTODETECT_NONE
	 */
	/**
	 *将自动检测模式设置为按名称使用。
	 *如果提供的值不可解析，则@throws IllegalArgumentException
	 *到｛@code AUTODETECT_｝常量之一或为｛@code-null｝
	 *@参见#setAutodetectMode（int）
	 *@参见#AUTODETECT_ALL
	 *@参见#AUTODETECT_ASSEMBLER
	 *@参见#AUTODETECT_MBEAN
	 *@参见#AUTODETECT_NONE
	 */
	public void setAutodetectModeName(String constantName) {
		if (!constantName.startsWith(CONSTANT_PREFIX_AUTODETECT)) {
			throw new IllegalArgumentException("Only autodetect constants allowed");
		}
		this.autodetectMode = (Integer) constants.asNumber(constantName);
	}

	/**
	 * Specify whether to allow eager initialization of candidate beans
	 * when autodetecting MBeans in the Spring application context.
	 * <p>Default is "false", respecting lazy-init flags on bean definitions.
	 * Switch this to "true" in order to search lazy-init beans as well,
	 * including FactoryBean-produced objects that haven't been initialized yet.
	 */
	/**
	 *指定是否允许对候选bean进行紧急初始化
	 *在Spring应用程序上下文中自动检测MBean时。
	 *＜p＞默认值为“false”，尊重bean定义上的惰性init标志。
	 *将其切换为“true”，以便也搜索懒惰的init bean，
	 *包括FactoryBean生成的尚未初始化的对象。
	 */
	public void setAllowEagerInit(boolean allowEagerInit) {
		this.allowEagerInit = allowEagerInit;
	}

	/**
	 * Set the implementation of the {@code MBeanInfoAssembler} interface to use
	 * for this exporter. Default is a {@code SimpleReflectiveMBeanInfoAssembler}.
	 * <p>The passed-in assembler can optionally implement the
	 * {@code AutodetectCapableMBeanInfoAssembler} interface, which enables it
	 * to participate in the exporter's MBean autodetection process.
	 * @see org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler
	 * @see org.springframework.jmx.export.assembler.AutodetectCapableMBeanInfoAssembler
	 * @see org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler
	 * @see #setAutodetect
	 */
	/**
	 *将｛@code MBeanInfoAssembler｝接口的实现设置为使用
	 *为这个出口商。默认值为｛@code SimpleReflectiveMBeanInfoAssembler｝。
	 *＜p＞传入的汇编程序可以选择性地实现
	 *｛@code AutodetectCapableMBeanInfoAssembler｝接口，使其能够
	 *参与出口商的MBean自动检测过程。
	 *@参见org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler
	 *@参见org.springframework.jmx.export.assembler.AutodetectCapableMBeanInfoAssembler
	 *@参见org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler
	 *@参见#setAutodetect
	 */
	public void setAssembler(MBeanInfoAssembler assembler) {
		this.assembler = assembler;
	}

	/**
	 * Set the implementation of the {@code ObjectNamingStrategy} interface
	 * to use for this exporter. Default is a {@code KeyNamingStrategy}.
	 * @see org.springframework.jmx.export.naming.KeyNamingStrategy
	 * @see org.springframework.jmx.export.naming.MetadataNamingStrategy
	 */
	/**
	 *设置｛@code ObjectNamingStrategy｝接口的实现
	 *用于该出口商。默认为｛@code KeyNamingStrategy｝。
	 *@参见org.springframework.jmx.export.naming.KeyNamingStrategy
	 *@参见org.springframework.jmx.export.naming.MetadataNamingStrategy
	 */
	public void setNamingStrategy(ObjectNamingStrategy namingStrategy) {
		this.namingStrategy = namingStrategy;
	}

	/**
	 * Indicates whether Spring should ensure that {@link ObjectName ObjectNames}
	 * generated by the configured {@link ObjectNamingStrategy} for
	 * runtime-registered MBeans ({@link #registerManagedResource}) should get
	 * modified: to ensure uniqueness for every instance of a managed {@code Class}.
	 * <p>The default value is {@code true}.
	 * @see #registerManagedResource
	 * @see JmxUtils#appendIdentityToObjectName(javax.management.ObjectName, Object)
	 */
	/**
	 *指示Spring是否应确保｛@link ObjectName ObjectNames｝
	 *由为配置的｛@link ObjectNamingStrategy｝生成
	 *运行时注册的MBean（{@link#registerManagedResource}）应该得到
	 *已修改：以确保托管｛@code Class｝的每个实例的唯一性。
	 *＜p＞默认值为｛@code true｝。
	 *@参见#registerManagedResource
	 *@参见JmxUtils#appendIdentityToObjectName（javax.management.ObjectName，Object）
	 */
	public void setEnsureUniqueRuntimeObjectNames(boolean ensureUniqueRuntimeObjectNames) {
		this.ensureUniqueRuntimeObjectNames = ensureUniqueRuntimeObjectNames;
	}

	/**
	 * Indicates whether the managed resource should be exposed on the
	 * {@link Thread#getContextClassLoader() thread context ClassLoader} before
	 * allowing any invocations on the MBean to occur.
	 * <p>The default value is {@code true}, exposing a {@link SpringModelMBean}
	 * which performs thread context ClassLoader management. Switch this flag off to
	 * expose a standard JMX {@link javax.management.modelmbean.RequiredModelMBean}.
	 */
	/**
	 *指示是否应在上公开托管资源
	 *｛@link Thread#getContextClassLoader（）线程上下文ClassLoader｝之前
	 *允许对MBean进行任何调用。
	 *＜p＞默认值为｛@code true｝，公开｛@link SpringModelMBean｝
	 *执行线程上下文ClassLoader管理。将此标志关闭为
	 *公开一个标准的JMX｛@link javax.management.modelmbean.RequiredModelMBean｝。
	 */
	public void setExposeManagedResourceClassLoader(boolean exposeManagedResourceClassLoader) {
		this.exposeManagedResourceClassLoader = exposeManagedResourceClassLoader;
	}

	/**
	 * Set the list of names for beans that should be excluded from autodetection.
	 */
	/**
	 *设置应从自动检测中排除的bean的名称列表。
	 */
	public void setExcludedBeans(String... excludedBeans) {
		this.excludedBeans.clear();
		Collections.addAll(this.excludedBeans, excludedBeans);
	}

	/**
	 * Add the name of bean that should be excluded from autodetection.
	 */
	/**
	 *添加应该从自动检测中排除的bean的名称。
	 */
	public void addExcludedBean(String excludedBean) {
		Assert.notNull(excludedBean, "ExcludedBean must not be null");
		this.excludedBeans.add(excludedBean);
	}

	/**
	 * Set the {@code MBeanExporterListener}s that should be notified
	 * of MBean registration and unregistration events.
	 * @see MBeanExporterListener
	 */
	/**
	 *设置应通知的｛@code MBeanExporterListener｝
	 *MBean注册和注销事件。
	 *@参见MBeanExporterListener
	 */
	public void setListeners(MBeanExporterListener... listeners) {
		this.listeners = listeners;
	}

	/**
	 * Set the {@link NotificationListenerBean NotificationListenerBeans}
	 * containing the
	 * {@link javax.management.NotificationListener NotificationListeners}
	 * that will be registered with the {@link MBeanServer}.
	 * @see #setNotificationListenerMappings(java.util.Map)
	 * @see NotificationListenerBean
	 */
	/**
	 *设置｛@link NotificationListenerBean NotificationListenerBeans｝
	 *包含
	 *｛@link javax.management.NotificationListener NotificationListeners｝
	 *将在｛@link MBeanServer｝中注册。
	 *@参见#setNotificationListenerMappings（java.util.Map）
	 *@see NotificationListenerBean
	 */
	public void setNotificationListeners(NotificationListenerBean... notificationListeners) {
		this.notificationListeners = notificationListeners;
	}

	/**
	 * Set the {@link NotificationListener NotificationListeners} to register
	 * with the {@link javax.management.MBeanServer}.
	 * <P>The key of each entry in the {@code Map} is a {@link String}
	 * representation of the {@link javax.management.ObjectName} or the bean
	 * name of the MBean the listener should be registered for. Specifying an
	 * asterisk ({@code *}) for a key will cause the listener to be
	 * associated with all MBeans registered by this class at startup time.
	 * <p>The value of each entry is the
	 * {@link javax.management.NotificationListener} to register. For more
	 * advanced options such as registering
	 * {@link javax.management.NotificationFilter NotificationFilters} and
	 * handback objects see {@link #setNotificationListeners(NotificationListenerBean[])}.
	 */
	/**
	 *将｛@link NotificationListener NotificationListeners｝设置为注册
	 *使用{@linkjavax.management.MBeanServer}。
	 *＜P＞｛@code Map｝中每个条目的键都是｛@link String｝
	 *｛@link javax.management.ObjectName｝或bean的表示形式
	 *应该为其注册侦听器的MBean的名称。指定
	 *键的星号（｛@code*｝）将导致侦听器
	 *与该类在启动时注册的所有MBean关联。
	 *<p>每个条目的值是
	 *｛@link javax.management.NotificationListener｝注册。了解更多信息
	 *高级选项，如注册
	 *｛@link javax.management.NotificationFilter NotificationFilters｝和
	 *handback对象请参见{@link#setNotificationListeners（NotificationListenerBean[]）}。
	 */
	public void setNotificationListenerMappings(Map<?, ? extends NotificationListener> listeners) {
		Assert.notNull(listeners, "'listeners' must not be null");
		List<NotificationListenerBean> notificationListeners =
				new ArrayList<>(listeners.size());

		listeners.forEach((key, listener) -> {
			// Get the listener from the map value.
			// 从映射值中获取侦听器。
			NotificationListenerBean bean = new NotificationListenerBean(listener);
			// Get the ObjectName from the map key.
			// 从映射键获取ObjectName。
			if (key != null && !WILDCARD.equals(key)) {
				// This listener is mapped to a specific ObjectName.
				// 此侦听器映射到特定的ObjectName。
				bean.setMappedObjectName(key);
			}
			notificationListeners.add(bean);
		});

		this.notificationListeners = notificationListeners.toArray(new NotificationListenerBean[0]);
	}

	@Override
	public void setBeanClassLoader(ClassLoader classLoader) {
		this.beanClassLoader = classLoader;
	}

	/**
	 * This callback is only required for resolution of bean names in the
	 * {@link #setBeans(java.util.Map) "beans"} {@link Map} and for
	 * autodetection of MBeans (in the latter case, a
	 * {@code ListableBeanFactory} is required).
	 * @see #setBeans
	 * @see #setAutodetect
	 */
	/**
	 *此回调仅用于解析中的bean名称
	 *｛@link#setBeans（java.util.Map）“beans”｝｛@link Map｝和
	 *MBean的自动检测（在后一种情况下
	 *｛@code ListableBeanFactory｝是必需的）。
	 *@见#setBeans
	 *@参见#setAutodetect
	 */
	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		if (beanFactory instanceof ListableBeanFactory) {
			this.beanFactory = (ListableBeanFactory) beanFactory;
		}
		else {
			logger.debug("MBeanExporter not running in a ListableBeanFactory: autodetection of MBeans not available.");
		}
	}


	//---------------------------------------------------------------------
	// ---------------------------------------------------------------------
	// Lifecycle in bean factory: automatically register/unregister beans
	// bean工厂中的生命周期：自动注册/注销bean
	//---------------------------------------------------------------------
	// ---------------------------------------------------------------------

	@Override
	public void afterPropertiesSet() {
		// If no server was provided then try to find one. This is useful in an environment
		// 如果没有提供服务器，请尝试查找一个。这在环境中很有用
		// where there is already an MBeanServer loaded.
		// 其中已经加载了MBeanServer。
		if (this.server == null) {
			this.server = JmxUtils.locateMBeanServer();
		}
	}

	/**
	 * Kick off bean registration automatically after the regular singleton instantiation phase.
	 * @see #registerBeans()
	 */
	/**
	 *在常规的单例实例化阶段之后，自动启动bean注册。
	 *@参见#registerBeans（）
	 */
	@Override
	public void afterSingletonsInstantiated() {
		try {
			logger.debug("Registering beans for JMX exposure on startup");
			registerBeans();
			registerNotificationListeners();
		}
		catch (RuntimeException ex) {
			// Unregister beans already registered by this exporter.
			// 注销此出口商已注册的豆子。
			unregisterNotificationListeners();
			unregisterBeans();
			throw ex;
		}
	}

	/**
	 * Unregisters all beans that this exported has exposed via JMX
	 * when the enclosing {@code ApplicationContext} is destroyed.
	 */
	/**
	 *注销此导出已通过JMX公开的所有bean
	 *当封闭的｛@code ApplicationContext｝被销毁时。
	 */
	@Override
	public void destroy() {
		logger.debug("Unregistering JMX-exposed beans on shutdown");
		unregisterNotificationListeners();
		unregisterBeans();
	}


	//---------------------------------------------------------------------
	// ---------------------------------------------------------------------
	// Implementation of MBeanExportOperations interface
	// MBeanExportOperations接口的实现
	//---------------------------------------------------------------------
	// ---------------------------------------------------------------------

	@Override
	public ObjectName registerManagedResource(Object managedResource) throws MBeanExportException {
		Assert.notNull(managedResource, "Managed resource must not be null");
		ObjectName objectName;
		try {
			objectName = getObjectName(managedResource, null);
			if (this.ensureUniqueRuntimeObjectNames) {
				objectName = JmxUtils.appendIdentityToObjectName(objectName, managedResource);
			}
		}
		catch (Throwable ex) {
			throw new MBeanExportException("Unable to generate ObjectName for MBean [" + managedResource + "]", ex);
		}
		registerManagedResource(managedResource, objectName);
		return objectName;
	}

	@Override
	public void registerManagedResource(Object managedResource, ObjectName objectName) throws MBeanExportException {
		Assert.notNull(managedResource, "Managed resource must not be null");
		Assert.notNull(objectName, "ObjectName must not be null");
		try {
			if (isMBean(managedResource.getClass())) {
				doRegister(managedResource, objectName);
			}
			else {
				ModelMBean mbean = createAndConfigureMBean(managedResource, managedResource.getClass().getName());
				doRegister(mbean, objectName);
				injectNotificationPublisherIfNecessary(managedResource, mbean, objectName);
			}
		}
		catch (JMException ex) {
			throw new UnableToRegisterMBeanException(
					"Unable to register MBean [" + managedResource + "] with object name [" + objectName + "]", ex);
		}
	}

	@Override
	public void unregisterManagedResource(ObjectName objectName) {
		Assert.notNull(objectName, "ObjectName must not be null");
		doUnregister(objectName);
	}


	//---------------------------------------------------------------------
	// ---------------------------------------------------------------------
	// Exporter implementation
	// 出口商实施
	//---------------------------------------------------------------------
	// ---------------------------------------------------------------------

	/**
	 * Register the defined beans with the {@link MBeanServer}.
	 * <p>Each bean is exposed to the {@code MBeanServer} via a
	 * {@code ModelMBean}. The actual implementation of the
	 * {@code ModelMBean} interface used depends on the implementation of
	 * the {@code ModelMBeanProvider} interface that is configured. By
	 * default, the {@code RequiredModelMBean} class that is supplied with
	 * all JMX implementations is used.
	 * <p>The management interface produced for each bean is dependent on the
	 * {@code MBeanInfoAssembler} implementation being used. The
	 * {@code ObjectName} given to each bean is dependent on the
	 * implementation of the {@code ObjectNamingStrategy} interface being used.
	 */
	/**
	 *向｛@link MBeanServer｝注册已定义的bean。
	 *<p>每个bean都通过
	 *｛@code ModelMBean｝。实际实施
	 *所使用的｛@code ModelMBean｝接口取决于
	 *配置的｛@code ModelMBeanProvider｝接口。通过
	 *默认情况下，提供的｛@code RequiredModelMBean｝类
	 *使用了所有的JMX实现。
	 *＜p＞为每个bean生成的管理接口依赖于
	 *｛@code MBeanInfoAssembler｝实现正在使用。这个
	 *给每个bean的｛@code ObjectName｝依赖于
	 *正在使用的｛@code ObjectNamingStrategy｝接口的实现。
	 */
	protected void registerBeans() {
		// The beans property may be null, for example if we are relying solely on autodetection.
		// beans属性可能为null，例如，如果我们仅依赖于自动检测。
		if (this.beans == null) {
			this.beans = new HashMap<>();
			// Use AUTODETECT_ALL as default in no beans specified explicitly.
			// 在没有明确指定bean的情况下，使用AUTODETECT_ALL作为默认值。
			if (this.autodetectMode == null) {
				this.autodetectMode = AUTODETECT_ALL;
			}
		}

		// Perform autodetection, if desired.
		// 如果需要，执行自动检测。
		int mode = (this.autodetectMode != null ? this.autodetectMode : AUTODETECT_NONE);
		if (mode != AUTODETECT_NONE) {
			if (this.beanFactory == null) {
				throw new MBeanExportException("Cannot autodetect MBeans if not running in a BeanFactory");
			}
			if (mode == AUTODETECT_MBEAN || mode == AUTODETECT_ALL) {
				// Autodetect any beans that are already MBeans.
				// 自动检测任何已经是MBean的bean。
				logger.debug("Autodetecting user-defined JMX MBeans");
				autodetect(this.beans, (beanClass, beanName) -> isMBean(beanClass));
			}
			// Allow the assembler a chance to vote for bean inclusion.
			// 允许汇编程序有机会投票支持bean包含。
			if ((mode == AUTODETECT_ASSEMBLER || mode == AUTODETECT_ALL) &&
					this.assembler instanceof AutodetectCapableMBeanInfoAssembler) {
				autodetect(this.beans, ((AutodetectCapableMBeanInfoAssembler) this.assembler)::includeBean);
			}
		}

		if (!this.beans.isEmpty()) {
			this.beans.forEach((beanName, instance) -> registerBeanNameOrInstance(instance, beanName));
		}
	}

	/**
	 * Return whether the specified bean definition should be considered as lazy-init.
	 * @param beanFactory the bean factory that is supposed to contain the bean definition
	 * @param beanName the name of the bean to check
	 * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#getBeanDefinition
	 * @see org.springframework.beans.factory.config.BeanDefinition#isLazyInit
	 */
	/**
	 *返回指定的bean定义是否应被视为惰性init。
	 *@param beanFactory应该包含bean定义的bean工厂
	 *@param beanName要检查的bean的名称
	 *@参见org.springframework.beans.factory.config.ConfiguratbleListableBeanFactory#getBeanDefinition
	 *@参见org.springframework.beans.factory.config.BeanDefinition#isLazyInit
	 */
	protected boolean isBeanDefinitionLazyInit(ListableBeanFactory beanFactory, String beanName) {
		return (beanFactory instanceof ConfigurableListableBeanFactory && beanFactory.containsBeanDefinition(beanName) &&
				((ConfigurableListableBeanFactory) beanFactory).getBeanDefinition(beanName).isLazyInit());
	}

	/**
	 * Register an individual bean with the {@link #setServer MBeanServer}.
	 * <p>This method is responsible for deciding <strong>how</strong> a bean
	 * should be exposed to the {@code MBeanServer}. Specifically, if the
	 * supplied {@code mapValue} is the name of a bean that is configured
	 * for lazy initialization, then a proxy to the resource is registered with
	 * the {@code MBeanServer} so that the lazy load behavior is
	 * honored. If the bean is already an MBean then it will be registered
	 * directly with the {@code MBeanServer} without any intervention. For
	 * all other beans or bean names, the resource itself is registered with
	 * the {@code MBeanServer} directly.
	 * @param mapValue the value configured for this bean in the beans map;
	 * may be either the {@code String} name of a bean, or the bean itself
	 * @param beanKey the key associated with this bean in the beans map
	 * @return the {@code ObjectName} under which the resource was registered
	 * @throws MBeanExportException if the export failed
	 * @see #setBeans
	 * @see #registerBeanInstance
	 * @see #registerLazyInit
	 */
	/**
	 *向｛@link#setServerMBeanServer｝注册单个bean。
	 *<p>此方法负责决定<strong>如何</strong>一个bean
	 *应该向｛@code MBeanServer｝公开。具体而言，如果
	 *provided｛@code-mapValue｝是已配置的bean的名称
	 *对于延迟初始化，则向注册资源的代理
	 *｛@code MBeanServer｝，以便延迟加载行为
	 *很荣幸。如果bean已经是MBean，那么它将被注册
	 *直接使用{@codeMBeanServer}，而无需任何干预。对于
	 *所有其他bean或bean名称，资源本身都使用
	 *｛@code MBeanServer｝。
	 *@param mapValue在beans映射中为该bean配置的值；
	 *可以是bean的{@codeString}名称，也可以是bean本身
	 *@param beanKey在beans映射中与该bean关联的键
	 *@返回用于注册资源的｛@code ObjectName｝
	 *如果导出失败，@throws MBeanExportException
	 *@见#setBeans
	 *@参见#registerBeanInstance
	 *@参见#registerLazyUnit
	 */
	protected ObjectName registerBeanNameOrInstance(Object mapValue, String beanKey) throws MBeanExportException {
		try {
			if (mapValue instanceof String beanName) {
				// Bean name pointing to a potentially lazy-init bean in the factory.
				// Bean名称指向工厂中一个潜在的惰性initbean。
				if (this.beanFactory == null) {
					throw new MBeanExportException("Cannot resolve bean names if not running in a BeanFactory");
				}
				if (isBeanDefinitionLazyInit(this.beanFactory, beanName)) {
					ObjectName objectName = registerLazyInit(beanName, beanKey);
					replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
					return objectName;
				}
				else {
					Object bean = this.beanFactory.getBean(beanName);
					ObjectName objectName = registerBeanInstance(bean, beanKey);
					replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
					return objectName;
				}
			}
			else {
				// Plain bean instance -> register it directly.
				// 普通bean实例->直接注册。
				if (this.beanFactory != null) {
					Map<String, ?> beansOfSameType =
							this.beanFactory.getBeansOfType(mapValue.getClass(), false, this.allowEagerInit);
					for (Map.Entry<String, ?> entry : beansOfSameType.entrySet()) {
						if (entry.getValue() == mapValue) {
							String beanName = entry.getKey();
							ObjectName objectName = registerBeanInstance(mapValue, beanKey);
							replaceNotificationListenerBeanNameKeysIfNecessary(beanName, objectName);
							return objectName;
						}
					}
				}
				return registerBeanInstance(mapValue, beanKey);
			}
		}
		catch (Throwable ex) {
			throw new UnableToRegisterMBeanException(
					"Unable to register MBean [" + mapValue + "] with key '" + beanKey + "'", ex);
		}
	}

	/**
	 * Replace any bean names used as keys in the {@code NotificationListener}
	 * mappings with their corresponding {@code ObjectName} values.
	 * @param beanName the name of the bean to be registered
	 * @param objectName the {@code ObjectName} under which the bean will be registered
	 * with the {@code MBeanServer}
	 */
	/**
	 *替换｛@code NotificationListener｝中用作键的任何bean名称
	 *映射及其对应的｛@code ObjectName｝值。
	 *@param beanName要注册的bean的名称
	 *@param objectName将在其下注册bean的｛@code objectName｝
	 *使用｛@code MBeanServer｝
	 */
	private void replaceNotificationListenerBeanNameKeysIfNecessary(String beanName, ObjectName objectName) {
		if (this.notificationListeners != null) {
			for (NotificationListenerBean notificationListener : this.notificationListeners) {
				notificationListener.replaceObjectName(beanName, objectName);
			}
		}
	}

	/**
	 * Registers an existing MBean or an MBean adapter for a plain bean
	 * with the {@code MBeanServer}.
	 * @param bean the bean to register, either an MBean or a plain bean
	 * @param beanKey the key associated with this bean in the beans map
	 * @return the {@code ObjectName} under which the bean was registered
	 * with the {@code MBeanServer}
	 */
	/**
	 *为普通bean注册现有的MBean或MBean适配器
	 *使用｛@code MBeanServer｝。
	 *@param-bean要注册的bean，MBean或普通bean
	 *@param beanKey在beans映射中与该bean关联的键
	 *@return注册bean的｛@code ObjectName｝
	 *使用｛@code MBeanServer｝
	 */
	private ObjectName registerBeanInstance(Object bean, String beanKey) throws JMException {
		ObjectName objectName = getObjectName(bean, beanKey);
		Object mbeanToExpose = null;
		if (isMBean(bean.getClass())) {
			mbeanToExpose = bean;
		}
		else {
			DynamicMBean adaptedBean = adaptMBeanIfPossible(bean);
			if (adaptedBean != null) {
				mbeanToExpose = adaptedBean;
			}
		}

		if (mbeanToExpose != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("Located MBean '" + beanKey + "': registering with JMX server as MBean [" +
						objectName + "]");
			}
			doRegister(mbeanToExpose, objectName);
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("Located managed bean '" + beanKey + "': registering with JMX server as MBean [" +
						objectName + "]");
			}
			ModelMBean mbean = createAndConfigureMBean(bean, beanKey);
			doRegister(mbean, objectName);
			injectNotificationPublisherIfNecessary(bean, mbean, objectName);
		}

		return objectName;
	}

	/**
	 * Register beans that are configured for lazy initialization with the
	 * {@code MBeanServer} indirectly through a proxy.
	 * @param beanName the name of the bean in the {@code BeanFactory}
	 * @param beanKey the key associated with this bean in the beans map
	 * @return the {@code ObjectName} under which the bean was registered
	 * with the {@code MBeanServer}
	 */
	/**
	 *使用注册为延迟初始化配置的bean
	 *｛@code MBeanServer｝间接通过代理。
	 *@param beanName｛@code BeanFactory｝中bean的名称
	 *@param beanKey在beans映射中与该bean关联的键
	 *@return注册bean的｛@code ObjectName｝
	 *使用｛@code MBeanServer｝
	 */
	private ObjectName registerLazyInit(String beanName, String beanKey) throws JMException {
		Assert.state(this.beanFactory != null, "No BeanFactory set");

		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.setProxyTargetClass(true);
		proxyFactory.setFrozen(true);

		if (isMBean(this.beanFactory.getType(beanName))) {
			// A straight MBean... Let's create a simple lazy-init CGLIB proxy for it.
			// 一个正直的MBean。。。让我们为它创建一个简单的惰性init-CGLIB代理。
			LazyInitTargetSource targetSource = new LazyInitTargetSource();
			targetSource.setTargetBeanName(beanName);
			targetSource.setBeanFactory(this.beanFactory);
			proxyFactory.setTargetSource(targetSource);

			Object proxy = proxyFactory.getProxy(this.beanClassLoader);
			ObjectName objectName = getObjectName(proxy, beanKey);
			if (logger.isDebugEnabled()) {
				logger.debug("Located MBean '" + beanKey + "': registering with JMX server as lazy-init MBean [" +
						objectName + "]");
			}
			doRegister(proxy, objectName);
			return objectName;
		}

		else {
			// A simple bean... Let's create a lazy-init ModelMBean proxy with notification support.
			// 一个简单的豆子。。。让我们创建一个具有通知支持的惰性initModelMBean代理。
			NotificationPublisherAwareLazyTargetSource targetSource = new NotificationPublisherAwareLazyTargetSource();
			targetSource.setTargetBeanName(beanName);
			targetSource.setBeanFactory(this.beanFactory);
			proxyFactory.setTargetSource(targetSource);

			Object proxy = proxyFactory.getProxy(this.beanClassLoader);
			ObjectName objectName = getObjectName(proxy, beanKey);
			if (logger.isDebugEnabled()) {
				logger.debug("Located simple bean '" + beanKey + "': registering with JMX server as lazy-init MBean [" +
						objectName + "]");
			}
			ModelMBean mbean = createAndConfigureMBean(proxy, beanKey);
			targetSource.setModelMBean(mbean);
			targetSource.setObjectName(objectName);
			doRegister(mbean, objectName);
			return objectName;
		}
	}

	/**
	 * Retrieve the {@code ObjectName} for a bean.
	 * <p>If the bean implements the {@code SelfNaming} interface, then the
	 * {@code ObjectName} will be retrieved using {@code SelfNaming.getObjectName()}.
	 * Otherwise, the configured {@code ObjectNamingStrategy} is used.
	 * @param bean the name of the bean in the {@code BeanFactory}
	 * @param beanKey the key associated with the bean in the beans map
	 * @return the {@code ObjectName} for the supplied bean
	 * @throws javax.management.MalformedObjectNameException
	 * if the retrieved {@code ObjectName} is malformed
	 */
	/**
	 *检索bean的｛@code ObjectName｝。
	 *＜p＞如果bean实现了｛@code SelfNaming｝接口，那么
	 *将使用｛@code SelfNaming.getObjectName（）｝检索｛@code ObjectName｝。
	 *否则，将使用已配置的｛@code ObjectNamingStrategy｝。
	 *@param bean｛@code BeanFactory｝中bean的名称
	 *@param beanKey与beans映射中的bean关联的键
	 *@为提供的bean返回｛@code ObjectName｝
	 *@throws javax.management.MalformedObjectName异常
	 *如果检索到的｛@code ObjectName｝格式不正确
	 */
	protected ObjectName getObjectName(Object bean, @Nullable String beanKey) throws MalformedObjectNameException {
		if (bean instanceof SelfNaming) {
			return ((SelfNaming) bean).getObjectName();
		}
		else {
			return this.namingStrategy.getObjectName(bean, beanKey);
		}
	}

	/**
	 * Determine whether the given bean class qualifies as an MBean as-is.
	 * <p>The default implementation delegates to {@link JmxUtils#isMBean},
	 * which checks for {@link javax.management.DynamicMBean} classes as well
	 * as classes with corresponding "*MBean" interface (Standard MBeans)
	 * or corresponding "*MXBean" interface (Java MXBeans).
	 * @param beanClass the bean class to analyze
	 * @return whether the class qualifies as an MBean
	 * @see org.springframework.jmx.support.JmxUtils#isMBean(Class)
	 */
	/**
	 *确定给定的bean类是否符合MBean的条件。
	 *<p>默认实现委托给{@link JmxUtils#isMBean}，
	 *它还检查{@link javax.management.DynamicMBean}类
	 *作为具有相应“*MBean”接口的类（标准MBean）
	 *或对应的“*MXBean”接口（Java MXBeans）。
	 *@param beanClass要分析的bean类
	 *@return类是否符合MBean的条件
	 *@参见org.springframework.jmx.support.JmxUtils#isMBean（类）
	 */
	protected boolean isMBean(@Nullable Class<?> beanClass) {
		return JmxUtils.isMBean(beanClass);
	}

	/**
	 * Build an adapted MBean for the given bean instance, if possible.
	 * <p>The default implementation builds a JMX 1.2 StandardMBean
	 * for the target's MBean/MXBean interface in case of an AOP proxy,
	 * delegating the interface's management operations to the proxy.
	 * @param bean the original bean instance
	 * @return the adapted MBean, or {@code null} if not possible
	 */
	/**
	 *如果可能的话，为给定的bean实例构建一个经过调整的MBean。
	 *＜p＞默认实现构建一个JMX 1.2 StandardMBean
	 *在AOP代理的情况下，对于目标的MBean/MXBean接口，
	 *将接口的管理操作委派给代理。
	 *@param-bean原始bean实例
	 *@返回经过调整的MBean，或者{@code null}（如果不可能）
	 */
	@SuppressWarnings("unchecked")
	@Nullable
	protected DynamicMBean adaptMBeanIfPossible(Object bean) throws JMException {
		Class<?> targetClass = AopUtils.getTargetClass(bean);
		if (targetClass != bean.getClass()) {
			Class<?> ifc = JmxUtils.getMXBeanInterface(targetClass);
			if (ifc != null) {
				if (!ifc.isInstance(bean)) {
					throw new NotCompliantMBeanException("Managed bean [" + bean +
							"] has a target class with an MXBean interface but does not expose it in the proxy");
				}
				return new StandardMBean(bean, ((Class<Object>) ifc), true);
			}
			else {
				ifc = JmxUtils.getMBeanInterface(targetClass);
				if (ifc != null) {
					if (!ifc.isInstance(bean)) {
						throw new NotCompliantMBeanException("Managed bean [" + bean +
								"] has a target class with an MBean interface but does not expose it in the proxy");
					}
					return new StandardMBean(bean, ((Class<Object>) ifc));
				}
			}
		}
		return null;
	}

	/**
	 * Creates an MBean that is configured with the appropriate management
	 * interface for the supplied managed resource.
	 * @param managedResource the resource that is to be exported as an MBean
	 * @param beanKey the key associated with the managed bean
	 * @see #createModelMBean()
	 * @see #getMBeanInfo(Object, String)
	 */
	/**
	 *创建使用适当管理配置的MBean
	 *提供的托管资源的接口。
	 *@param managedResource要导出为MBean的资源
	 *@param beanKey与托管bean关联的密钥
	 *@参见#createModelMBean（）
	 *@参见#getMBeanInfo（对象，字符串）
	 */
	protected ModelMBean createAndConfigureMBean(Object managedResource, String beanKey)
			throws MBeanExportException {
		try {
			ModelMBean mbean = createModelMBean();
			mbean.setModelMBeanInfo(getMBeanInfo(managedResource, beanKey));
			mbean.setManagedResource(managedResource, MR_TYPE_OBJECT_REFERENCE);
			return mbean;
		}
		catch (Throwable ex) {
			throw new MBeanExportException("Could not create ModelMBean for managed resource [" +
					managedResource + "] with key '" + beanKey + "'", ex);
		}
	}

	/**
	 * Create an instance of a class that implements {@code ModelMBean}.
	 * <p>This method is called to obtain a {@code ModelMBean} instance to
	 * use when registering a bean. This method is called once per bean during the
	 * registration phase and must return a new instance of {@code ModelMBean}
	 * @return a new instance of a class that implements {@code ModelMBean}
	 * @throws javax.management.MBeanException if creation of the ModelMBean failed
	 */
	/**
	 *创建实现｛@code ModelMBean｝的类的实例。
	 *<p>调用此方法以获得｛@code ModelMBean｝实例
	 *注册bean时使用。在
	 *注册阶段，并且必须返回｛@code ModelMBean｝的新实例
	 *@返回实现｛@code ModelMBean｝的类的新实例
	 *@throws javax.management.MBea如果创建ModelMBean失败则异常
	 */
	protected ModelMBean createModelMBean() throws MBeanException {
		return (this.exposeManagedResourceClassLoader ? new SpringModelMBean() : new RequiredModelMBean());
	}

	/**
	 * Gets the {@code ModelMBeanInfo} for the bean with the supplied key
	 * and of the supplied type.
	 */
	/**
	 *获取具有所提供键的bean的｛@code ModelMBeanInfo｝
	 *并且是所提供的类型。
	 */
	private ModelMBeanInfo getMBeanInfo(Object managedBean, String beanKey) throws JMException {
		ModelMBeanInfo info = this.assembler.getMBeanInfo(managedBean, beanKey);
		if (logger.isInfoEnabled() && ObjectUtils.isEmpty(info.getAttributes()) &&
				ObjectUtils.isEmpty(info.getOperations())) {
			logger.info("Bean with key '" + beanKey +
					"' has been registered as an MBean but has no exposed attributes or operations");
		}
		return info;
	}


	//---------------------------------------------------------------------
	// ---------------------------------------------------------------------
	// Autodetection process
	// 自动检测过程
	//---------------------------------------------------------------------
	// ---------------------------------------------------------------------

	/**
	 * Performs the actual autodetection process, delegating to an
	 * {@code AutodetectCallback} instance to vote on the inclusion of a
	 * given bean.
	 * @param callback the {@code AutodetectCallback} to use when deciding
	 * whether to include a bean or not
	 */
	/**
	 *执行实际的自动检测过程，委派给
	 *｛@code AutodetectCallback｝实例投票决定是否包含
	 *给定的bean。
	 *@param回调决定时使用的｛@code AutodetectCallback｝
	 *是否包含bean
	 */
	private void autodetect(Map<String, Object> beans, AutodetectCallback callback) {
		Assert.state(this.beanFactory != null, "No BeanFactory set");
		Set<String> beanNames = new LinkedHashSet<>(this.beanFactory.getBeanDefinitionCount());
		Collections.addAll(beanNames, this.beanFactory.getBeanDefinitionNames());
		if (this.beanFactory instanceof ConfigurableBeanFactory) {
			Collections.addAll(beanNames, ((ConfigurableBeanFactory) this.beanFactory).getSingletonNames());
		}

		for (String beanName : beanNames) {
			if (!isExcluded(beanName) && !isBeanDefinitionAbstract(this.beanFactory, beanName)) {
				try {
					Class<?> beanClass = this.beanFactory.getType(beanName);
					if (beanClass != null && callback.include(beanClass, beanName)) {
						boolean lazyInit = isBeanDefinitionLazyInit(this.beanFactory, beanName);
						Object beanInstance = null;
						if (!lazyInit) {
							beanInstance = this.beanFactory.getBean(beanName);
							if (!beanClass.isInstance(beanInstance)) {
								continue;
							}
						}
						if (!ScopedProxyUtils.isScopedTarget(beanName) && !beans.containsValue(beanName) &&
								(beanInstance == null ||
										!CollectionUtils.containsInstance(beans.values(), beanInstance))) {
							// Not already registered for JMX exposure.
							// 尚未注册JMX曝光。
							beans.put(beanName, (beanInstance != null ? beanInstance : beanName));
							if (logger.isDebugEnabled()) {
								logger.debug("Bean with name '" + beanName + "' has been autodetected for JMX exposure");
							}
						}
						else {
							if (logger.isTraceEnabled()) {
								logger.trace("Bean with name '" + beanName + "' is already registered for JMX exposure");
							}
						}
					}
				}
				catch (CannotLoadBeanClassException ex) {
					if (this.allowEagerInit) {
						throw ex;
					}
					// otherwise ignore beans where the class is not resolvable
					// 否则忽略类不可解析的bean
				}
			}
		}
	}

	/**
	 * Indicates whether a particular bean name is present in the excluded beans list.
	 */
	/**
	 *指示排除的bean列表中是否存在特定的bean名称。
	 */
	private boolean isExcluded(String beanName) {
		return (this.excludedBeans.contains(beanName) ||
					(beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX) &&
							this.excludedBeans.contains(beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length()))));
	}

	/**
	 * Return whether the specified bean definition should be considered as abstract.
	 */
	/**
	 *返回指定的bean定义是否应被视为抽象的。
	 */
	private boolean isBeanDefinitionAbstract(ListableBeanFactory beanFactory, String beanName) {
		return (beanFactory instanceof ConfigurableListableBeanFactory && beanFactory.containsBeanDefinition(beanName) &&
				((ConfigurableListableBeanFactory) beanFactory).getBeanDefinition(beanName).isAbstract());
	}


	//---------------------------------------------------------------------
	// ---------------------------------------------------------------------
	// Notification and listener management
	// 通知和侦听器管理
	//---------------------------------------------------------------------
	// ---------------------------------------------------------------------

	/**
	 * If the supplied managed resource implements the {@link NotificationPublisherAware} an instance of
	 * {@link org.springframework.jmx.export.notification.NotificationPublisher} is injected.
	 */
	/**
	 *如果提供的托管资源实现了的｛@link NotificationPublisherware｝实例
	 *｛@link org.springframework.jmx.exexport.notification.NotificationPublisher｝被注入。
	 */
	private void injectNotificationPublisherIfNecessary(
			Object managedResource, @Nullable ModelMBean modelMBean, @Nullable ObjectName objectName) {

		if (managedResource instanceof NotificationPublisherAware && modelMBean != null && objectName != null) {
			((NotificationPublisherAware) managedResource).setNotificationPublisher(
					new ModelMBeanNotificationPublisher(modelMBean, objectName, managedResource));
		}
	}

	/**
	 * Register the configured {@link NotificationListener NotificationListeners}
	 * with the {@link MBeanServer}.
	 */
	/**
	 *注册已配置的｛@link NotificationListener NotificationListeners｝
	 *使用{@link MBeanServer}。
	 */
	private void registerNotificationListeners() throws MBeanExportException {
		if (this.notificationListeners != null) {
			Assert.state(this.server != null, "No MBeanServer available");
			for (NotificationListenerBean bean : this.notificationListeners) {
				try {
					ObjectName[] mappedObjectNames = bean.getResolvedObjectNames();
					if (mappedObjectNames == null) {
						// Mapped to all MBeans registered by the MBeanExporter.
						// 映射到由MBeanExporter注册的所有MBean。
						mappedObjectNames = getRegisteredObjectNames();
					}
					if (this.registeredNotificationListeners.put(bean, mappedObjectNames) == null) {
						for (ObjectName mappedObjectName : mappedObjectNames) {
							this.server.addNotificationListener(mappedObjectName, bean.getNotificationListener(),
									bean.getNotificationFilter(), bean.getHandback());
						}
					}
				}
				catch (Throwable ex) {
					throw new MBeanExportException("Unable to register NotificationListener", ex);
				}
			}
		}
	}

	/**
	 * Unregister the configured {@link NotificationListener NotificationListeners}
	 * from the {@link MBeanServer}.
	 */
	/**
	 *注销已配置的｛@link NotificationListener NotificationListeners｝
	 *来自｛@link MBeanServer｝。
	 */
	private void unregisterNotificationListeners() {
		if (this.server != null) {
			this.registeredNotificationListeners.forEach((bean, mappedObjectNames) -> {
				for (ObjectName mappedObjectName : mappedObjectNames) {
					try {
						this.server.removeNotificationListener(mappedObjectName, bean.getNotificationListener(),
								bean.getNotificationFilter(), bean.getHandback());
					}
					catch (Throwable ex) {
						if (logger.isDebugEnabled()) {
							logger.debug("Unable to unregister NotificationListener", ex);
						}
					}
				}
			});
		}
		this.registeredNotificationListeners.clear();
	}

	/**
	 * Called when an MBean is registered. Notifies all registered
	 * {@link MBeanExporterListener MBeanExporterListeners} of the registration event.
	 * <p>Please note that if an {@link MBeanExporterListener} throws a (runtime)
	 * exception when notified, this will essentially interrupt the notification process
	 * and any remaining listeners that have yet to be notified will not (obviously)
	 * receive the {@link MBeanExporterListener#mbeanRegistered(javax.management.ObjectName)}
	 * callback.
	 * @param objectName the {@code ObjectName} of the registered MBean
	 */
	/**
	 *在注册MBean时调用。通知所有注册的
	 *注册事件的｛@link MBeanExporterListener MBeanExporter Listeners｝。
	 *<p>请注意，如果｛@link MBeanExporterListener｝抛出（运行时）
	 *通知时出现异常，这将实质上中断通知过程
	 *而任何尚未得到通知的剩余侦听器将不会（显然）
	 *接收{@link MBeanExporterListener#mbeanRegistered（javax.management.ObjectName）}
	 *回调。
	 *@param objectName已注册MBean的｛@code objectName｝
	 */
	@Override
	protected void onRegister(ObjectName objectName) {
		notifyListenersOfRegistration(objectName);
	}

	/**
	 * Called when an MBean is unregistered. Notifies all registered
	 * {@link MBeanExporterListener MBeanExporterListeners} of the unregistration event.
	 * <p>Please note that if an {@link MBeanExporterListener} throws a (runtime)
	 * exception when notified, this will essentially interrupt the notification process
	 * and any remaining listeners that have yet to be notified will not (obviously)
	 * receive the {@link MBeanExporterListener#mbeanUnregistered(javax.management.ObjectName)}
	 * callback.
	 * @param objectName the {@code ObjectName} of the unregistered MBean
	 */
	/**
	 *在未注册MBean时调用。通知所有注册的
	 *注销事件的｛@link MBeanExporterListener MBeanExporter Listeners｝。
	 *<p>请注意，如果｛@link MBeanExporterListener｝抛出（运行时）
	 *通知时出现异常，这将实质上中断通知过程
	 *而任何尚未得到通知的剩余侦听器将不会（显然）
	 *接收｛@link MBeanExporterListener#mbeanUnregistered（javax.management.ObjectName）｝
	 *回调。
	 *@param objectName未注册MBean的｛@code objectName｝
	 */
	@Override
	protected void onUnregister(ObjectName objectName) {
		notifyListenersOfUnregistration(objectName);
	}


	/**
	 * Notifies all registered {@link MBeanExporterListener MBeanExporterListeners} of the
	 * registration of the MBean identified by the supplied {@link ObjectName}.
	 */
	/**
	 *通知所有已注册的｛@link MBeanExporterListener MBeanExporter Listeners｝
	 *由提供的｛@link ObjectName｝标识的MBean的注册。
	 */
	private void notifyListenersOfRegistration(ObjectName objectName) {
		if (this.listeners != null) {
			for (MBeanExporterListener listener : this.listeners) {
				listener.mbeanRegistered(objectName);
			}
		}
	}

	/**
	 * Notifies all registered {@link MBeanExporterListener MBeanExporterListeners} of the
	 * unregistration of the MBean identified by the supplied {@link ObjectName}.
	 */
	/**
	 *通知所有已注册的｛@link MBeanExporterListener MBeanExporter Listeners｝
	 *由提供的｛@link ObjectName｝标识的MBean的注销。
	 */
	private void notifyListenersOfUnregistration(ObjectName objectName) {
		if (this.listeners != null) {
			for (MBeanExporterListener listener : this.listeners) {
				listener.mbeanUnregistered(objectName);
			}
		}
	}


	//---------------------------------------------------------------------
	// ---------------------------------------------------------------------
	// Inner classes for internal use
	// 内部使用的内部类
	//---------------------------------------------------------------------
	// ---------------------------------------------------------------------

	/**
	 * Internal callback interface for the autodetection process.
	 */
	/**
	 *自动检测进程的内部回调接口。
	 */
	@FunctionalInterface
	private interface AutodetectCallback {

		/**
		 * Called during the autodetection process to decide whether
		 * a bean should be included.
		 * @param beanClass the class of the bean
		 * @param beanName the name of the bean
		 */
		/**
		 *在自动检测过程中调用以决定是否
		 *应该包括一个bean。
		 *@param beanClass bean的类
		 *@param beanName bean的名称
		 */
		boolean include(Class<?> beanClass, String beanName);
	}


	/**
	 * Extension of {@link LazyInitTargetSource} that will inject a
	 * {@link org.springframework.jmx.export.notification.NotificationPublisher}
	 * into the lazy resource as it is created if required.
	 */
	/**
	 *｛@link LazyInitTargetSource｝的扩展，该扩展将注入
	 *｛@link org.springframework.jmx.exexport.notification.NotificationPublisher｝
	 *如果需要的话，在创建惰性资源时将其转换为惰性资源。
	 */
	@SuppressWarnings("serial")
	private class NotificationPublisherAwareLazyTargetSource extends LazyInitTargetSource {

		@Nullable
		private ModelMBean modelMBean;

		@Nullable
		private ObjectName objectName;

		public void setModelMBean(ModelMBean modelMBean) {
			this.modelMBean = modelMBean;
		}

		public void setObjectName(ObjectName objectName) {
			this.objectName = objectName;
		}

		@Override
		@Nullable
		public Object getTarget() {
			try {
				return super.getTarget();
			}
			catch (RuntimeException ex) {
				if (logger.isInfoEnabled()) {
					logger.info("Failed to retrieve target for JMX-exposed bean [" + this.objectName + "]: " + ex);
				}
				throw ex;
			}
		}

		@Override
		protected void postProcessTargetObject(Object targetObject) {
			injectNotificationPublisherIfNecessary(targetObject, this.modelMBean, this.objectName);
		}
	}

}
